package com.apes.fn.fico.debitnote.service;

import com.alibaba.fastjson.JSONObject;
import com.apes.fn.fico.debitnote.model.BusinessDebitNote;
import com.apes.fn.fico.debitnote.repository.BusinessDebitNoteRepository;
import com.apes.fn.scm.contract.FnContract;
import com.apes.fn.scm.contract.FnContractRepository;
import com.apes.fn.scm.merchant.account.model.MerchantAccountSettlement;
import com.apes.fn.scm.merchant.account.model.SettlementCostSummary;
import com.apes.fn.scm.merchant.account.model.SettlementIncomeSummary;
import com.apes.fn.scm.merchant.account.repository.AccountSettlementRepository;
import com.apes.fn.scm.merchant.account.service.AccountSettlementService;
import com.apes.fn.scm.merchant.settlement.model.CostSummary;
import com.apes.fn.scm.merchant.settlement.model.MerchantSettlement;
import com.apes.fn.scm.merchant.settlement.repository.CostSummaryRepository;
import com.apes.fn.scm.merchant.settlement.repository.MerchantSettlementRepository;
import com.apes.fn.scm.merchant.settlement.service.MerchantSettlementService;
import com.apes.fn.scm.prepare.model.Prepare;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.*;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.income.repository.IncomeItemRepository;
import com.apes.scm.masterdata.frame.model.Store;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.frame.repository.StoreRepository;
import com.apes.scm.masterdata.party.model.AccessProvider;
import com.apes.scm.masterdata.party.repository.AccessProviderRepository;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.settle.payment.model.Payment;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.VoucherType;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Creator: zouyc
 * CreateDate: 2019-12-23 9:12
 * Description:
 **/
@Service("businessDebitNoteService")
public class BusinessDebitNoteService extends DomainService {
    @Autowired
    private BusinessDebitNoteRepository businessDebitNoteRepository;

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Autowired
    private FnContractRepository fnContractRepository;

    @Autowired
    private AccountSettlementService accountSettlementService;

    @Autowired
    private AccountSettlementRepository accountSettlementRepository;

    @Autowired
    private MerchantSettlementRepository merchantSettlementRepository;

    public BusinessDebitNote create(SimpleRequest request) {
        BusinessDebitNote businessDebitNote = request.getO(BusinessDebitNote.class);
        BusinessDebitNote businessDebitNoteState = businessDebitNoteRepository.findBysaleDeptIdAndState(businessDebitNote.getSaleDept().getId(), "create");
        if (Objects.nonNull(businessDebitNoteState))
            throw new RuntimeException("该部门存在创建状态的预支单:"+businessDebitNoteState.getId()+"，请先提交或删除此单！");
        if (businessDebitNote.getPriceDebit() < 1) throw new RuntimeException("请填写预支金额(元)！！！");
        businessDebitNote.setState("create");
        businessDebitNote.setWithhold("unwithheld");
        businessDebitNote.setAccountName(businessDebitNote.getBankAccount().getId());
        List<FnContract> fnContractList = fnContractRepository.findAll(JpaDsl.toCriteriaByEq("partner.id", businessDebitNote.getFnCustomer().getId(), "state", "approve"));
        if (fnContractList.size() == 0) throw new RuntimeException("没有赋能合同，提示该公司不存在有效合同，请确认！");
        if (fnContractList.size() > 1) throw new RuntimeException("赋能合同存在多个有效合同，请确认！");
        if (!StringUtils.isEmpty(businessDebitNote.getReason()) && businessDebitNote.getReason().length() > 30)
            throw new RuntimeException("预支说明数量不能大于30，请修改！");
        Store store = SpringManager.getBean(StoreRepository.class).findOne(SpringManager.getBean(DeptRepository.class).findByPartyRoleAndDeptType(businessDebitNote.getFnCustomer().getId(), "000007").getId());
        if (Objects.isNull(store.getFnTag())) throw new RuntimeException("该商户名下部门没有赋能标签，请先联系行政人员维护，再预支！");
        businessDebitNote.setFnTag(store.getFnTag());//赋能标签

        if (Objects.isNull(businessDebitNote.getId())) {
            //常备库存金额 同2.0 商品批次
            businessDebitNote.setStandingInventoryAmount(SpringManager.getBean(InventoryBatchRepository.class).findStandingInventoryAmount(businessDebitNote.getFnCustomer().getId()));
            //保证金额度 赋能合同
            businessDebitNote.setFnTag(store.getFnTag());
            double guaranteedAmount = fnContractList.stream().mapToDouble(FnContract::getStoreDeposit).sum();
            businessDebitNote.setGuaranteedAmount(Arith.round(guaranteedAmount, 2));
            //常备库存定金 赋能合同
            double standingInventoryDeposit = fnContractList.stream().mapToDouble(FnContract::getStockDeposit).sum();
            businessDebitNote.setStandingInventoryDeposit(Arith.round(standingInventoryDeposit, 2));
        }

        return businessDebitNoteRepository.saveAndFlush(businessDebitNote);
    }


    public String delete(SimpleRequest request) {
        BusinessDebitNote businessDebitNote = request.getO(BusinessDebitNote.class);
        if (businessDebitNote == null) throw new RuntimeException("营业借支款：" + request.get("id") + " 在系统中不存在。");
        if (businessDebitNote.getState() == "apply")
            throw new RuntimeException("营业借支款：" + request.get("id") + " 在系统中已提交。");
        businessDebitNoteRepository.delete(businessDebitNote);
        return "删除成功！";
    }

    public BusinessDebitNote submit(SimpleRequest request) {
        BusinessDebitNote businessDebitNote = request.getO(BusinessDebitNote.class);
        businessDebitNote.setState("apply");
        businessDebitNote.setSubmitDate(new Date());
        businessDebitNote.setSubmitUid(getPerson(request));
        businessDebitNote.setPriceDebit(Arith.round(businessDebitNote.getPriceDebit(), 2));
        businessDebitNote = businessDebitNoteRepository.saveAndFlush(businessDebitNote);
        return businessDebitNote;
    }

    public BusinessDebitNote approve(SimpleRequest request) {
        BusinessDebitNote businessDebitNote = request.getO(BusinessDebitNote.class);
        if (businessDebitNote.getAvailableLoan() == 0) throw new RuntimeException("可预支金额错误，请确认！");
        businessDebitNote.setState("pending");
        businessDebitNote.setApproveDate(new Date());
        businessDebitNote.setApproveUid(this.getPerson(request));
        businessDebitNote = businessDebitNoteRepository.saveAndFlush(businessDebitNote);
        return businessDebitNote;
    }

    /**
     * 审批拒绝 终止
     *
     * @param request
     * @return
     */
    public BusinessDebitNote refuse(SimpleRequest request) {
        BusinessDebitNote businessDebitNote = request.getO(BusinessDebitNote.class);
        businessDebitNote.setState("delete");
        return businessDebitNoteRepository.saveAndFlush(businessDebitNote);
    }


    public BusinessDebitNote queryMethod(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String merchantId = requestJO.getString("fnCustomerId");

        BusinessDebitNote businessDebitNote = new BusinessDebitNote();
        //常备库存金额 同2.0 商品批次
        businessDebitNote.setStandingInventoryAmount(SpringManager.getBean(InventoryBatchRepository.class).findStandingInventoryAmount(merchantId));
        //保证金额度 赋能合同
        List<FnContract> fnContractList = fnContractRepository.findAll(JpaDsl.toCriteriaByEq("partner.id", merchantId, "state", "approve"));
        if (fnContractList.size() == 0) throw new RuntimeException("没有赋能合同，提示该公司不存在有效合同，请确认！");
        if (fnContractList.size() > 1) throw new RuntimeException("赋能合同存在多个有效合同，请确认！");
        double guaranteedAmount = fnContractList.stream().mapToDouble(FnContract::getStoreDeposit).sum();
        double baseDeposit = fnContractList.stream().mapToDouble(FnContract::getBaseDeposit).sum();
        businessDebitNote.setGuaranteedAmount(Arith.round(guaranteedAmount + baseDeposit, 2));//门店保证金(元/店)+基地保证金(元/店)
        //常备库存定金 赋能合同
        double standingInventoryDeposit = fnContractList.stream().mapToDouble(FnContract::getStockDeposit).sum();
        businessDebitNote.setStandingInventoryDeposit(Arith.round(standingInventoryDeposit, 2));//常备库存定金(万元/店)
        return businessDebitNote;
    }


    /**
     * 获取商户信息
     *
     * @param request
     * @return
     */
    public Map getBusinessInformation(SimpleRequest request) {
        if (request.getJO().getString("merchantId") == null) {
            return null;
        }
        String merchantId = request.get("merchantId");
        Map result = new HashMap();
        //获取接入商
        AccessProvider accessProvider = SpringManager.getBean(AccessProviderRepository.class).findByCompany(merchantId);
        if (accessProvider == null) {
            throw new RuntimeException("该商户无接入商！请检查商户数据");
        }
        result.put("accessProvider", accessProvider);
        result.put("accessDate", accessProvider.getCreateDate());
        //获取门店数
        List<Store> stores = SpringManager.getBean(StoreRepository.class).findAll(JpaDsl.toCriteriaByEq("company.id", merchantId));
        result.put("numberOfStore", stores.size());
        //获取营业额
        YearMonth yearMonth = YearMonth.now();
        YearMonth minusMonths = YearMonth.now().minusMonths(1);
        //检查本月该商户是否已对账
        //取本月第一天
        Date firstDayOfMonth = Date.from(LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth()).atZone(ZoneId.systemDefault()).toInstant());
        MerchantSettlement merchantSettlement = SpringManager.getBean(MerchantSettlementRepository.class).findByMerchantAndDate(merchantId, firstDayOfMonth, new Date()).stream().findFirst().orElse(null);
        if (merchantSettlement != null && firstDayOfMonth.before(merchantSettlement.getReconcileEndDate())) {
            //已对账
            List<Map> sumBusinessTurnoverDataBayDay = getSumBusinessTurnoverDataBayDay(merchantId, merchantSettlement.getReconcileEndDate());
            if (sumBusinessTurnoverDataBayDay.isEmpty()) {
                result.put("currentMonthTurnover", 0);
            } else {
                result.put("currentMonthTurnover", sumBusinessTurnoverDataBayDay.get(0).get("SALE_MONEY") == null ? 0 : sumBusinessTurnoverDataBayDay.get(0).get("SALE_MONEY"));
            }
            // 获取成本
            MerchantSettlementService settlementService = SpringManager.getBean(MerchantSettlementService.class);
            Date date = DateUtil.add(merchantSettlement.getReconcileEndDate(), Calendar.DAY_OF_MONTH, 1);
            result.put("costAmount", Arith.round(settlementService.getTheTotal(SpringManager.getBean(VoucherRepository.class).findByCompanyAndVoucherType(merchantId, VoucherType.SUPPLIER_CONSUME, InventoryMode.IM_CONSIGN, date, new Date()), "priceTotal") + settlementService.getTheTotal(SpringManager.getBean(VoucherRepository.class).findByCompanyAndVoucherType(merchantId, VoucherType.SUPPLIER_PURCHASE, InventoryMode.IM_OWN, date, new Date()), "priceTotal"), 2));
            //预算款
            result.put("unDeductedBudgetAmount", merchantSettlement.getCostSummaries().stream().filter(costSummary -> LogicalUtil.in(costSummary.getCostSummaryType().getId(), "platformFee", "businessDebit")).mapToDouble(CostSummary::getRemainingDeductibleBalance).sum());
        } else {
            List<Map> businessTurnoverData = getSumBusinessTurnoverData(merchantId, Integer.parseInt(yearMonth.toString().replace("-", "")));
            if (businessTurnoverData.isEmpty()) {
                result.put("currentMonthTurnover", 0);
            } else {
                result.put("currentMonthTurnover", businessTurnoverData.get(0).get("SALE_MONEY") == null ? 0 : businessTurnoverData.get(0).get("SALE_MONEY"));
            }
            // 获取成本
            MerchantSettlementService settlementService = SpringManager.getBean(MerchantSettlementService.class);
            result.put("costAmount", Arith.round(settlementService.getTheTotal(SpringManager.getBean(VoucherRepository.class).findByCompanyAndVoucherType(merchantId, VoucherType.SUPPLIER_CONSUME, InventoryMode.IM_CONSIGN, firstDayOfMonth, new Date()), "priceTotal") + settlementService.getTheTotal(SpringManager.getBean(VoucherRepository.class).findByCompanyAndVoucherType(merchantId, VoucherType.SUPPLIER_PURCHASE, InventoryMode.IM_OWN, firstDayOfMonth, new Date()), "priceTotal"), 2));
            //预算款
            result.put("unDeductedBudgetAmount", 0);

        }
        List<Map> sumBusinessTurnoverData = getSumBusinessTurnoverData(merchantId, Integer.parseInt(minusMonths.toString().replace("-", "")));
        if (sumBusinessTurnoverData.isEmpty()) {
            result.put("lastMonthTurnover", 0);
        } else {
            result.put("lastMonthTurnover", sumBusinessTurnoverData.get(0).get("SALE_MONEY") == null ? 0 : sumBusinessTurnoverData.get(0).get("SALE_MONEY"));
        }
        // 获取当前常备库存
        result.put("standingInventoryAmount", SpringManager.getBean(InventoryBatchRepository.class).findStandingInventoryAmount(merchantId));

        //获取未扣收借款金额
        double sumUnpaidPrincipal = businessDebitNoteRepository.findAllByFnCustomerId(merchantId).stream().mapToDouble(BusinessDebitNote::getUnpaidPrincipal).sum();
        result.put("unDeductedLoanAmount", sumUnpaidPrincipal);
        return result;
    }


    /**
     * 获取未扣收借款项
     *
     * @param request
     * @return
     */
    public JSONObject findBusinessDebit(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        JSONObject object = new JSONObject();
        JSONObject data = requestJO.getJSONObject("data");
        if (data == null) {
            data = requestJO;
        }
        String merchantId = data.getString("fnCustomerId");
        Date createDate = new Date();
        if (data.getDate("createDate") != null) {
            createDate = data.getDate("createDate");
        }
        List<BusinessDebitNote> businessDebitNotes = businessDebitNoteRepository.findAllByFnCustomerIdAndCreateDate(merchantId, createDate);
        object.put("content", businessDebitNotes);
        return object;
    }

    /**
     * 获取对账单成本项
     *
     * @param request
     * @return
     */
    public JSONObject findCostSummary(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        JSONObject object = new JSONObject();
        JSONObject data = requestJO.getJSONObject("data");
        if (data == null) {
            data = requestJO;
        }
        String merchantId = data.getString("fnCustomerId");
        Date createDate = new Date();
        if (data.getDate("createDate") != null) {
            createDate = data.getDate("createDate");
        }
        //取该月第一天
        LocalDateTime localDateTime = createDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        Date firstDayOfMonth = Date.from(localDateTime.with(TemporalAdjusters.firstDayOfMonth()).atZone(ZoneId.systemDefault()).toInstant());
        List<MerchantSettlement> merchantSettlements = SpringManager.getBean(MerchantSettlementRepository.class).findByMerchantAndDate(merchantId, firstDayOfMonth, createDate);
        List<JSONObject> list = new ArrayList<>();
        merchantSettlements.forEach(merchantSettlement -> {
            List<CostSummary> costSummaries = SpringManager.getBean(CostSummaryRepository.class).findAllByMerchantSettlement(merchantSettlement.getId());
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            costSummaries.stream().filter(costSummary -> LogicalUtil.in(costSummary.getCostSummaryType().getId(), "platformFee", "businessDebit")).forEach((result) -> {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("merchantSettlementId", result.getMerchantSettlement().getId());
                jsonObject.put("description", result.getCostSummaryType().getDescription());
                jsonObject.put("remainingDeductibleBalance", result.getRemainingDeductibleBalance());
                jsonObject.put("reconcileBeginDate", dateFormat.format(result.getMerchantSettlement().getReconcileBeginDate()));
                jsonObject.put("reconcileEndDate", dateFormat.format(result.getMerchantSettlement().getReconcileEndDate()));
                list.add(jsonObject);
            });
        });

        object.put("content", list);
        return object;
    }


    /**
     * 获取商户营业总额数据
     *
     * @param merchantId
     * @param yearMonth
     * @return
     */
    public List<Map> getSumBusinessTurnoverData(String merchantId, int yearMonth) {
        //取结果集
        String sb = "   SELECT SUM(SALE_MONEY) SALE_MONEY " + "        FROM RCL_DAILYSALESREPORT_MONTH U\n" + "      WHERE 1 = 1 \n" + " AND COMPANY_ID=:COMPANY_ID AND YEAR_AND_MONTH=:yearMonth";
        Query query = entityManager.createNativeQuery(sb);
        query.setParameter("yearMonth", yearMonth);
        query.setParameter("COMPANY_ID", merchantId);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
        List<Map> resultList = query.getResultList();
        return resultList;
    }

    /**
     * 获取商户营业总额数据
     *
     * @param merchantId
     * @param date
     * @return
     */
    public List<Map> getSumBusinessTurnoverDataBayDay(String merchantId, Date date) {
        //取结果集
        String sb = "   SELECT SUM(SALE_MONEY) SALE_MONEY " + "        FROM RCL_DAILYSALESREPORT U\n" + "      WHERE 1 = 1 \n" + " AND COMPANY_ID=:COMPANY_ID AND DATE_OF_STATISTICS >:DATE_OF_STATISTICS AND DATE_OF_STATISTICS <=:nowaDay ";
        Query query = entityManager.createNativeQuery(sb);
        query.setParameter("DATE_OF_STATISTICS", date);
        query.setParameter("nowaDay", new Date());
        query.setParameter("COMPANY_ID", merchantId);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
        List<Map> resultList = query.getResultList();
        return resultList;
    }

    /**
     * OA流程
     *
     * @param request
     * @return
     */
    private BusinessDebitNote OAFlag(SimpleRequest request) {
        BusinessDebitNote businessDebitNote = request.getO(BusinessDebitNote.class);
        businessDebitNote.setPic(true);
        return businessDebitNote;
    }


    /**
     * OA流程
     *
     * @param request
     * @return
     */
    private BusinessDebitNote modifyReceipt(SimpleRequest request) {
        BusinessDebitNote businessDebitNote = request.getO(BusinessDebitNote.class);
        return businessDebitNoteRepository.saveAndFlush(businessDebitNote);
    }

    /**
     * 对账组填写预支起止。实预支金额
     *
     * @param request
     * @return
     */
    public BusinessDebitNote reconciliation(SimpleRequest request) {

        BusinessDebitNote businessDebitNote = request.getO(BusinessDebitNote.class);
        BusinessDebitNote businessDebit = businessDebitNoteRepository.findOne(businessDebitNote.getId());
        if ("0".equals(request.getJO().get("wf_variable_wf_state"))) {
            businessDebitNote.setState("create");
        } else if ("1".equals(request.getJO().get("wf_variable_wf_state"))) {
            if (Objects.isNull(businessDebitNote.getBorrowingDate()) || Objects.isNull(businessDebitNote.getLimitDate()) || businessDebitNote.getCapitalBalance() == 0)
                throw new RuntimeException("请选择预期间和填写实预支金额！");
            if (businessDebitNote.getCapitalBalance() < 0) throw new RuntimeException("实预支金额不能小于0，请重新确认！");
            if (businessDebitNote.getCapitalBalance() > businessDebitNote.getAvailableLoan())
                throw new RuntimeException("实预支金额大于可预支金额,请修改！");
            if (businessDebitNote.getAvailableLoan() == 0) throw new RuntimeException("可预支金额错误，请确认！");
            businessDebitNote.setCount(1);
        }

        businessDebitNote.setVersion(businessDebit.getVersion());
        businessDebitNote.setBankAccount(businessDebit.getBankAccount());
        businessDebitNote.setUnpaidPrincipal(businessDebitNote.getCapitalBalance());
        businessDebitNote.setUnDeductedLoanAmount(businessDebitNote.getCapitalBalance());

        businessDebitNote = businessDebitNoteRepository.saveAndFlush(businessDebitNote);
        businessDebitNote.setWrite(false);
        return businessDebitNote;
    }

    /**
     * 赋能支持经理拒绝
     *
     * @param request
     * @return
     */
    public BusinessDebitNote reject(SimpleRequest request) {
        BusinessDebitNote businessDebitNote = request.getO(BusinessDebitNote.class);
        if ("0".equals(request.getJO().get("wf_variable_wf_state"))) return businessDebitNote;
        if (Objects.isNull(businessDebitNote.getBorrowingDate()) || Objects.isNull(businessDebitNote.getLimitDate()) || businessDebitNote.getCapitalBalance() <= 0)
            throw new RuntimeException("请选择预期间和填写实预支金额！");
        if (businessDebitNote.getCapitalBalance() > businessDebitNote.getAvailableLoan())
            throw new RuntimeException("实预支金额大于可预支金额,请修改！");
        if (businessDebitNote.getAvailableLoan() == 0) throw new RuntimeException("可预支金额错误，请确认！");
        businessDebitNote = businessDebitNoteRepository.saveAndFlush(businessDebitNote);
        businessDebitNote.setWrite(false);

        return businessDebitNote;
    }


    /**
     * 获取有效的收款信息
     *
     * @param request
     * @return
     */
    public Map OAQuery(SimpleRequest request) {
        JSONObject param = request.getJO();
        Calendar c = Calendar.getInstance();

        Date borrowingDate = DateUtil.dateToDate(param.getDate("borrowingDate"), DateUtil.SHOW_DATE_FORMAT);//预支期起
        Date limitDate = DateUtil.dateToDate(param.getDate("limitDate"), DateUtil.SHOW_DATE_FORMAT);

        Date date = DateUtil.dateToDate(new Date(), DateUtil.SHOW_DATE_FORMAT);
        if (limitDate.getTime() < borrowingDate.getTime()) throw new RuntimeException("预支期起不能小于预支期止，请重新选择！");
        if (limitDate.getTime() >= date.getTime()) throw new RuntimeException("已选择日期大于或等于当前日期，请重新选择！");

        c.setTime(limitDate);
        c.add(Calendar.DATE, 1);

        //商户
        JSONObject object = request.get("fnCustomerId");
        String fnCustomerId = object.getString("id");

        BusinessDebitNote businessDebitNote = businessDebitNoteRepository.findOne(param.getString("id"));
        Map<String, Object> map = new HashMap<>();

        //向赋能商户结算对账单2.0取营业支出，营业收入，分期剩余未扣收金额，分期剩余未扣收金额
        settlement(borrowingDate, limitDate, fnCustomerId, map);

        map.put("availableLoan", Arith.round(Double.valueOf(map.get("currentMonthTurnover").toString()) - Double.valueOf(map.get("costAmount").toString()) + Double.valueOf(map.get("unDeductedBudgetAmount").toString()) - businessDebitNote.getAmount(), 2));
        return map;
    }

    private Map<String, Object> settlement(Date borrowingDate, Date limitDate, String fnCustomerId, Map<String, Object> map) {
        List<MerchantAccountSettlement> settlementList = accountSettlementRepository.findByMaxReconcileEndDate(fnCustomerId);
        List<MerchantSettlement> byMaxReconcileEndDate = merchantSettlementRepository.findByMaxReconcileEndDate(fnCustomerId);
        if (settlementList.size() > 1 || byMaxReconcileEndDate.size() > 1)
            throw new RuntimeException(String.format("获取上期对账单异常！存在多张上期对账单！请检查数据!"));

        accountSettlementService.getThePreviousMerchantSettlement(borrowingDate,fnCustomerId);

        MerchantAccountSettlement thePreviousMerchantSettlement = settlementList.size() > 0 ? settlementList.get(0) : null;

        MerchantSettlement previousMerchantSettlement = byMaxReconcileEndDate.size() > 0 ? byMaxReconcileEndDate.get(0) : null;
        Map<String, CostSummary> costSummaryMap = previousMerchantSettlement == null ? new HashMap<>() : previousMerchantSettlement.getCostSummaries().stream().collect(Collectors.toMap(costSummary -> costSummary.getCostSummaryType().getId(), costSummary -> costSummary, (k1, k2) -> k1));

        List<SettlementIncomeSummary> settlementIncomeSummaries = accountSettlementService.writeIncomeMethod(fnCustomerId, borrowingDate, limitDate, new MerchantAccountSettlement(), thePreviousMerchantSettlement);
        map.put("currentMonthTurnover", Arith.round(settlementIncomeSummaries.stream().mapToDouble(SettlementIncomeSummary::getAmountPayable).sum(), 2));

        MerchantAccountSettlement settlement = new MerchantAccountSettlement();
        List<SettlementCostSummary> settlementCostSummaries = accountSettlementService.writeCostMethod(fnCustomerId, borrowingDate, limitDate, thePreviousMerchantSettlement, settlement, costSummaryMap);
        settlement.setCostSummaries(settlementCostSummaries);
        settlement.setReconcileEndDate(limitDate);
        accountSettlementService.getBusinessDebitItem(fnCustomerId, settlement);
        accountSettlementService.getExpenseItems(fnCustomerId, settlement);
        double currentPeriodActualDeducted = settlement.getCostSummaries().stream().mapToDouble(SettlementCostSummary::getCurrentPeriodActualDeducted).sum();
        map.put("costAmount", Arith.round(currentPeriodActualDeducted, 2));

        if (Objects.nonNull(thePreviousMerchantSettlement)) {
            map.put("unDeductedBudgetAmount", thePreviousMerchantSettlement.getSettleBusinessMoneyTotal() > 0 ? 0 : thePreviousMerchantSettlement.getSettleBusinessMoneyTotal());
            map.put("totalUnDeductedCost", thePreviousMerchantSettlement.getTotalUnDeductedCost());
        } else {
            map.put("unDeductedBudgetAmount", 0);
            map.put("totalUnDeductedCost", 0);
        }
        return map;
    }

    /**
     * 付款单回写预支单
     *
     * @param request
     */
    public void payment(SimpleRequest request) {
        Map<String, Object> map = new HashMap<>(request.get("data"));
        Payment payment = (Payment) map.get("payment");

        List<BusinessDebitNote> businessDebitNotes = new ArrayList<>();
        payment.getPaymentItemSet().stream().forEach(v -> {
            if (Objects.isNull(v.getSource())) return;
            BusinessDebitNote businessDebitNote = businessDebitNoteRepository.findOne(v.getSource());
            if (Objects.isNull(businessDebitNote)) return;
            if (Objects.isNull(payment.getFileAddres())) throw new RuntimeException("需要上传付款回执,请上传！！");
            businessDebitNote.setLoanDate(new Date());
            businessDebitNote.setPrincipalRepaid(businessDebitNote.getPrincipalRepaid() + v.getAmount());//已付款
            businessDebitNote.setUnpaidPrincipal(businessDebitNote.getUnpaidPrincipal() - v.getAmount());//未付款
            businessDebitNote.setFileAddres(payment.getFileAddres());//付款回执
            if (businessDebitNote.getPrincipalRepaid() == businessDebitNote.getCapitalBalance()) {//当付款金额=实预支金额时
                businessDebitNote.setState("paid");//已付款
            } else {
                businessDebitNote.setState("pay");//部分付款
            }
            businessDebitNotes.add(businessDebitNote);
        });
        businessDebitNoteRepository.saveAll(businessDebitNotes);
    }

    /**
     * 缴款单生成预支单
     *
     * @param request
     */
    public BusinessDebitNote prepare(SimpleRequest request) {
        Prepare prepare = request.getO(Prepare.class);
        BusinessDebitNote businessDebitNote = new BusinessDebitNote();
        BusinessDebitNote byReasonLike = businessDebitNoteRepository.findByReasonLike(prepare.getId());
        if (Objects.nonNull(byReasonLike))
            throw new RuntimeException(prepare.getId() + "已生成预支单:" + byReasonLike.getId() + ",无法重复生成,请确认!");

        List<FnContract> fnContractList = fnContractRepository.findAll(JpaDsl.toCriteriaByEq("partner.id", prepare.getDept().getCompany().getId(), "state", "approve"));
        if (fnContractList.size() == 0) throw new RuntimeException("没有赋能合同，提示该公司不存在有效合同，请确认！");
        if (fnContractList.size() > 1) throw new RuntimeException("赋能合同存在多个有效合同，请确认！");
        Store store = SpringManager.getBean(StoreRepository.class).findOne(SpringManager.getBean(DeptRepository.class).findByPartyRoleAndDeptType(prepare.getDept().getCompany().getId(), "000007").getId());
        if (Objects.isNull(store.getFnTag())) throw new RuntimeException("该商户名下部门没有赋能标签，请先联系行政人员维护，再预支！");
        businessDebitNote.setFnTag(store.getFnTag());//赋能标签
        businessDebitNote.setPriceDebit(prepare.getPrepareAmount());//预支金额=缴款金额
        businessDebitNote.setCapitalBalance(prepare.getPrepareAmount());//实预支金额=缴款金额
        businessDebitNote.setUnDeductedLoanAmount(businessDebitNote.getCapitalBalance());//未扣收预支金额 = 实预支金额
        businessDebitNote.setSaleDept(prepare.getDept());//商户下销售部门=缴款单部门
        businessDebitNote.setFnCustomer(prepare.getDept().getCompany());//商户=缴款单部门下的公司
        businessDebitNote.setBankAccount(prepare.getRefundAccount());//银行账户
        businessDebitNote.setAccountName(prepare.getRefundAccount().getAccountName());//户名=缴款平台账户下的户名
        businessDebitNote.setAccountId(prepare.getRefundAccount().getAccountId());//银行账户=门店回款账户下的银行账户
        businessDebitNote.setBank(prepare.getRefundAccount().getBank());//银行=缴款单 门店回款账户下的银行
        businessDebitNote.setReason(prepare.getId() + "自动生成的预支单!");//预支说明
        businessDebitNote.setState("pending");//创建状态
        businessDebitNote.setWithhold("unwithheld");//扣收状态
        businessDebitNote.setCreator(prepare.getAdvanceUid().getId());//创建人
        businessDebitNote.setCreateDate(prepare.getAdvanceDate());//创建日期
        businessDebitNote.setBorrowingDate(prepare.getAdvanceDate());//预支期起
        businessDebitNote.setLimitDate(prepare.getAdvanceDate());//预支期止
        businessDebitNote.setApproveDate(new Date());//审批日期
        businessDebitNote.setApproveUid(prepare.getAdvanceUid());//审批人
        return businessDebitNoteRepository.saveAndFlush(businessDebitNote);
    }
}
